KERNEL_VERSION = "1.0"
KERNEL_API_COMPATIBLE = ["0.1", "0.2", "0.3", "0.4", "0.4A", "0.5", "0.6", "0.7", "0.8", "0.9", "1.0"]
KERNEL_TYPE = 1
KERNEL_NAME = "Rubik"
BASE_KERNEL_PATH = "/"
AUTORUN_PATH = BASE_KERNEL_PATH + 'autorun'

import os, sys, json
os.chdir(BASE_KERNEL_PATH + 'kernel/')

sys.path.append(BASE_KERNEL_PATH + 'kernel/')
sys.path.append(BASE_KERNEL_PATH)
sys.path.append(BASE_KERNEL_PATH + 'kernel/modules')
sys.path.append(BASE_KERNEL_PATH + 'kernel/modules/temp')
sys.path.append(BASE_KERNEL_PATH + 'kernel/modules/camera')
sys.path.append(BASE_KERNEL_PATH + 'kernel/modules/air_quality')
sys.path.append(BASE_KERNEL_PATH + 'kernel/modules/ethernet')
sys.path.append(BASE_KERNEL_PATH + 'kernel/modules/servo')


from Logger import Logger
from singleton import singleton

@singleton
class SystemLogger(Logger):
    Prefix = "[ Kernel ]"
    Separator = "::"
    LogFormat = f'%prefix% %separator% %text%'
    def __init__(self): pass

import machine, sys, gc, os

print('\033[2J') # Clear screen
SystemLogger().log("Staring Rubik3 kernel for QubicOS...")

config = {
    "tmp": {
        "enabled": False,
        "size": 25
    },

    "network": {
        "enabled": False,
    },

    "init": {
        "enabled": True,
        "app": "ush.py",
        "startgccontainer": False,
    },

    "ulp": {
        "enabled": False
    },

    "autostartenabled": True,
    "memdumpatpanic": True,
    
    "overclocking": {
        "cpu_freq": False
    }
}

# TODO: модули ядра

try:
    config = json.load(open(BASE_KERNEL_PATH + "kernel/config/kernel_conf.json"))
    SystemLogger().log("Using kernel_config.json")
except Exception as e:
    SystemLogger().log(f"Cannot load kernel config: {e}. Using default config")

SystemLogger().log(f"Detected platform: {sys.platform} CPU @ {machine.freq() // 1000000} MHz")
SystemLogger().log(f"Byteorder: {sys.byteorder}")
SystemLogger().log(f"Machine ID: {machine.unique_id()}")

if config["overclocking"]["cpu_freq"]: 
    SystemLogger().log(f'CPU Overclocking enabled. New CPU freq: {config["overclocking"]["cpu_freq"]}')
    machine.freq(config["overclocking"]["cpu_freq"])

if not "tmp" in os.listdir('/') and config["tmp"]["enabled"]:
    try:
        SystemLogger().log("Mounting /tmp ram disk")
        from BlockDevices.RAMFS import RAMBlockDev

        TMP_SIZE = config["tmp"]["size"]

        bdev = RAMBlockDev(512, 2 * TMP_SIZE) #  ~25 KB
        os.VfsFat.mkfs(bdev)
        os.mount(bdev, '/tmp')

        SystemLogger().log("/tmp Mounted")
    except:
        SystemLogger().log("Failed mounting /tmp")
else:
    SystemLogger().log("/tmp already mounted")

SystemLogger().log("Initializing Container subsystem")

from Containers.Container import ContainerPool

if config["network"]["enabled"]:
    SystemLogger().log("Starting NetStart Container")

    ContainerPool().CreateContainer("netstart_service", execfile)
    ContainerPool().GetContainer("netstart_service").start([BASE_KERNEL_PATH + "apps/netstart.py"])

    SystemLogger().log("Configuring network...")

SystemLogger().log("Freeing unused kernel image (initmem) memory...")
import gc
freed = gc.collect()
SystemLogger().log(f"Total free mem: {gc.mem_free()}")

ULP_SUBSYSTEM_ENABLED = config["ulp"]["enabled"]
if ULP_SUBSYSTEM_ENABLED:
    SystemLogger().log("Initializing Ultra Low Power CoProcessor(ULP) system...")
    import ULP

data = f"""
CPU        : N/A
Cache      : N/A
JTAG       : N/A
ULP        : N/A
Revision   : N/A
CPU MHz    : {machine.freq() / 1000000}
ID         : {machine.unique_id()}
DSP        : N/A
PSRAM      : N/A
Ethernet   : N/A
RTC Memory : N/A
PMU        : Enabled
SRAM       : N/A

Features   : N/A
"""

if config["tmp"]["enabled"]:
    for line in data.split('\n'):
        if not line == '': SystemLogger().log(line)

    with open('/tmp/cpuinfo', 'w') as file:
        file.write(data)

GC_COLLECT_PERIOD_MS = 2500

import time

def gc_collect(_):
    gc.collect()
    time.sleep(GC_COLLECT_PERIOD_MS)

if config["init"]["startgccontainer"]:
    SystemLogger().log("Starting GC Service container")

    ContainerPool().CreateContainer("gc_service", gc_collect)
    ContainerPool().GetContainer("gc_service").start([])

#SystemLogger().log("Starting FTP server")
#ContainerPool().CreateContainer("uftpd", execfile)
#ContainerPool().GetContainer("uftpd").start([BASE_KERNEL_PATH + "apps/ftpservice.py"])

WELCOME = 'Rubik3 3.10 Kernel for QubicOS, Build #62'

SystemLogger().log(WELCOME)

if config["autostartenabled"]:
    SystemLogger().log("Starting auto start apps...")
    try:
        files = os.listdir(AUTORUN_PATH)

        for file in files:
            execfile(AUTORUN_PATH + "/" + file)
    except Exception as e:
        SystemLogger().log("System excepted non-fatal error at run auto start apps: {e}")

if config["init"]["enabled"]:
    SystemLogger().log("Starting init_app from kernel_config")

    #ContainerPool().CreateContainer("ushell_service", lambda: execfile(BASE_KERNEL_PATH + "apps/ush.py", {"syscall": Pipe, "BASE_KERNEL_PATH": BASE_KERNEL_PATH}))
    #ContainerPool().GetContainer("ushell_service").start([])
    try:
        execfile(BASE_KERNEL_PATH + "apps/" + config["init"]["app"])
    except Exception as e:
        SystemLogger().log(f"System Halted, init_app performed an illegal operation and was stopped. error: {e}")
        import micropython, machine, time
        
        if config['memdumpatpanic']:
            SystemLogger().log("Dumping memory...")
            micropython.mem_info(True)
        SystemLogger().log("System will automatic reset in 20 seconds.")
        time.sleep(20)
        machine.reset()
else:
    SystemLogger().log("System Halted, no init_app in kernel_config.")

while True:
    time.sleep(1)
